Skip to content

[Server] Untangle origin tracking from Registry#302

Open
chr-hertel wants to merge 1 commit into
mainfrom
refactor/untangle-registry-origin
Open

[Server] Untangle origin tracking from Registry#302
chr-hertel wants to merge 1 commit into
mainfrom
refactor/untangle-registry-origin

Conversation

@chr-hertel
Copy link
Copy Markdown
Member

Summary

  • Drops isManual from ElementReference (and the four subclasses); origin is no longer a property of the element.
  • Strips clear() / getDiscoveryState() / setDiscoveryState() from RegistryInterface; the Registry is now a flat last-write-wins map.
  • Adds idempotent unregisterTool/Resource/ResourceTemplate/Prompt(string) to RegistryInterface.
  • Rewrites DiscoveryLoader with a private owned-set diff so re-running load() only removes elements this loader itself contributed — preserves runtime registrations between discovery passes.
  • Introduces ChainLoader for explicit composition; Builder::build() composes loaders internally so the user-facing API is unchanged.
  • Manual-over-discovered precedence is preserved via loader ordering ([user, discovery, manual] — last-write-wins).

Supersedes #251: the runtime-registration regression that PR was fixing dissolves by construction, without adding a second origin flag (isDiscovered).

Test plan

  • make ci — phpstan clean, php-cs-fixer clean, 652 unit tests / 2146 assertions pass.
  • make inspector-tests — 87 tests pass (7 environmental skips, same as main).
  • New DiscoveryLoaderTest::testLoadDoesNotUnregisterRuntimeAdditions locks in the regression that [Server] fix: clear() wiping dynamically registered tools by tracking discovered state on references #251 was after.
  • combined-registration example still works end-to-end; the config://priority resource correctly resolves to the manual override (3 inspector snapshots updated to reflect this — they were previously showing the discovered version winning, which was a latent bug).

Breaking changes

  • ElementReference->isManual property removed.
  • RegistryInterface::register*() signatures lose the bool $isManual = false parameter.
  • RegistryInterface::clear(), getDiscoveryState(), setDiscoveryState() removed (only correct caller was DiscoveryLoader, which no longer needs them).

Pre-1.0, internal area — no userland impact known beyond what's documented above.

@chr-hertel chr-hertel force-pushed the refactor/untangle-registry-origin branch 6 times, most recently from 1864939 to 483922c Compare May 11, 2026 20:11
@chr-hertel
Copy link
Copy Markdown
Member Author

@soyuka that could be an alternative approach to #251, removing the leaky isManual and isolating it in that DiscoveryLoader

@chr-hertel chr-hertel force-pushed the refactor/untangle-registry-origin branch 5 times, most recently from ab11794 to ea5c5ec Compare May 11, 2026 21:18
@chr-hertel chr-hertel added the Server Issues & PRs related to the Server component label May 11, 2026
Drop the isManual flag from ElementReference and the discovery-state methods
from RegistryInterface. The Registry becomes a flat last-write-wins map;
DiscoveryLoader owns its own owned-set bookkeeping so re-running discovery
only removes elements it itself contributed. Adds ChainLoader for explicit
composition. Manual-over-discovered precedence is preserved via loader
ordering, not a flag on the reference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chr-hertel chr-hertel force-pushed the refactor/untangle-registry-origin branch from ea5c5ec to 2c2456f Compare May 11, 2026 22:13
@soyuka
Copy link
Copy Markdown
Contributor

soyuka commented May 12, 2026

indeed, its a bit more complex then just a boolean though but I like the approach let me review.

Copy link
Copy Markdown
Contributor

@soyuka soyuka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed this can replace my monkey patch its cleaner :)

*/
final class DiscoveryLoader implements LoaderInterface
{
private DiscoveryState $owned;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private DiscoveryState $owned;
private DiscoveryState $owned = new DiscoveryState();

private array $namePatterns = DiscovererInterface::DEFAULT_NAME_PATERNS,
private LoggerInterface $logger = new NullLogger(),
) {
$this->owned = new DiscoveryState();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->owned = new DiscoveryState();

Comment thread src/Server/Builder.php
foreach ($loaders as $loader) {
$loader->load($registry);
}
$loader = 1 === \count($loaders) ? $loaders[0] : new ChainLoader($loaders);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$loader = 1 === \count($loaders) ? $loaders[0] : new ChainLoader($loaders);
$loader = new ChainLoader($loaders);

is probably fine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Server Issues & PRs related to the Server component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants